#pragma once

#include <cstdlib>
#include <cstring>

class Sensor {
  private:
      unsigned int *dates; // дата в днях
      unsigned int *times; // время в секундах
      bool *undefined;
      double *values;
      unsigned int num,mem_num; // число элементов в массивах 'dates', 'times' и 'undefined'
      unsigned int val_num,val_mem_num; // число элементов в массиве 'values'
      
  private:
      // динамическое увеличение памяти под один из массивов
      template<typename T> unsigned int inc_mem (T* &ptr, const unsigned int _num, const unsigned int m_num) {
	  if (_num==m_num)
	  {
	      if (m_num==0u)
	      {
		  ptr=static_cast<T*>(malloc(5u*sizeof(T)));
		  return 5u;
	      }
	      ptr=static_cast<T*>(realloc(ptr,(m_num+m_num)*sizeof(T)));
	      return (m_num+m_num); // в 2 раза
	  }
	  return m_num;
      }
      
  public:
      Sensor () {
	  dates=times=NULL;
	  undefined=NULL;
	  values=NULL;
	  num=mem_num=val_num=val_mem_num=0u;
      }
      
      ~Sensor () {
	  free(values);
	  free(undefined);
	  free(times);
	  free(dates);
      }
      
      // добавление нового показания данного датчика
      void Add (const unsigned int days, const unsigned int seconds, const bool undefd, const double value) {
	  inc_mem(dates,num,mem_num);
	  inc_mem(times,num,mem_num);
	  mem_num=inc_mem(undefined,num,mem_num);
	  dates[num]=days;
	  times[num]=seconds;
	  undefined[num]=undefd;
	  ++num;
	  if (!undefd)
	  {
	      val_mem_num=inc_mem(values,val_num,val_mem_num);
	      values[val_num++]=value;
	  }
      }
      
      // получение минимального и максимального значения показаний датчика, 
      // лежащих в интервале [(min_date,min_time);(max_date,max_time)]
      void GetMinMaxVal (const unsigned int min_date, const unsigned int min_time, 
			  const unsigned int max_date, const unsigned int max_time, 
			  double &min_val, double &max_val) const {
	  unsigned int j=0u;
	  for (unsigned int i=0u; i!=val_num; ++i)
	  {
	      if (undefined[i]) continue;
	      if (((dates[i]>min_date) || ((dates[i]==min_date) && (times[i]>=min_time))) && 
		  ((dates[i]<max_date) || ((dates[i]==max_date) && (times[i]<=max_time))))
	      {
		  min_val=(values[j]<min_val)? values[j] : min_val;
		  max_val=(values[j]>max_val)? values[j] : max_val;
	      }
	      ++j;
	  }
      }
      
      // установка заданной точности числа, переведённого в строку
      static void GetRealNumEnd (char *num, char* &num_end) {
	  static const int precision=4;
	  char *pt;
	  
	  num_end=num+strlen(num);
	  pt=strchr(num,'.');
	  if (pt!=NULL)
	  {
	      if (num_end-pt>precision) num_end=pt+precision+1;
	      for (--num_end; *num_end=='0'; --num_end) ;
	      if (*num_end!='.') ++num_end;
	  }
	  else
	  {
	      pt=strchr(num,',');
	      if (pt!=NULL)
	      {
		  if (num_end-pt>precision) num_end=pt+precision+1;
		  for (--num_end; *num_end=='0'; --num_end) ;
		  if (*num_end!=',') ++num_end;
	      }
	  }
	  *num_end='\0';
      }
      
      // рисование "обычного" графика для данного датчика
      void Draw (void*, const unsigned int, const unsigned int, const unsigned int, const unsigned int, 
		 const double, const double, const double, const double, const double, const int) const;
		 
      // рисование областей отклонения от среднего для данного датчика
      void DrawAvg1 (void*, const unsigned int, const unsigned int, const unsigned int, const unsigned int, const unsigned int, 
		     const double, const double, const double, const double, const double, const double) const;
		     
      // рисование графика усреднённых значений для данного датчика
      void DrawAvg2 (void*, const unsigned int, const unsigned int, const unsigned int, const unsigned int, const unsigned int, 
		     const double, const double, const double, const double, const double, const double) const;
};
